﻿using System;
using System.Linq;
using Microsoft.Office.Core;
using Microsoft.Office.Interop.PowerPoint;
using Shape = Microsoft.Office.Interop.PowerPoint.Shape;

namespace Microsoft.Office.PowerPoint.STAMP.Core
{
    /// <summary>
    /// A media shape in Stamp.
    /// </summary>
    public class StampMediaShape
    {
        private readonly Shape _mediaShape;
        private readonly string _mediaName;

        /// <summary>
        /// Initializes a new instance of the <see cref="StampMediaShape"/> class.
        /// </summary>
        /// <param name="mediaShape">The media shape.</param>
        public StampMediaShape(Shape mediaShape)
        {
            if (mediaShape.Type != MsoShapeType.msoMedia)
                throw new ArgumentException("The given shape is not a media shape.");
            _mediaShape = mediaShape;
            string shapeFullName = mediaShape.Name;
            _mediaName = shapeFullName.Substring(0, shapeFullName.LastIndexOf("."));
            if (String.IsNullOrEmpty(_mediaShape.Tags[MediaShapeTags.CaptionMediaId]))
            {
                _mediaShape.Tags.Add(MediaShapeTags.CaptionMediaId, Guid.NewGuid().ToString());
            }
        }

        /// <summary>
        /// Gets a value indicating whether captions for the media shape should be hidden.
        /// </summary>
        public bool IsCaptionsHidden
        {
            get
            {
                if (!String.IsNullOrEmpty(_mediaShape.Tags[MediaShapeTags.MediaCaptionsHidden]))
                {
                    return Boolean.Parse(_mediaShape.Tags[MediaShapeTags.MediaCaptionsHidden]);
                }
                return false;
            }
        }

        /// <summary>
        /// Gets the caption id.
        /// </summary>
        public string CaptionMediaId
        {
            get { return _mediaShape.Tags[MediaShapeTags.CaptionMediaId]; }
        }

        /// <summary>
        /// Gets a value indicating whether this instance has saved captions.
        /// </summary>
        public bool HasSavedCaptions
        {
            get
            {
                bool result;
                return bool.TryParse(_mediaShape.Tags[MediaShapeTags.MediaShapeHasCaptions], out result) && result;
            }

            set { _mediaShape.Tags.Add(MediaShapeTags.MediaShapeHasCaptions, value.ToString()); }
        }

        /// <summary>
        /// Gets the custom XML part id.
        /// </summary>
        public string CustomXMLPartId
        {
            get { return _mediaShape.Tags[MediaShapeTags.CustomXMLPartId]; }
            set { _mediaShape.Tags.Add(MediaShapeTags.CustomXMLPartId, value); }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is a movie.
        /// </summary>
        public bool IsMovie
        {
            get { return _mediaShape.MediaType == PpMediaType.ppMediaTypeMovie; }
        }

        /// <summary>
        /// Gets the width of the media.
        /// </summary>
        public float Width
        {
            get { return _mediaShape.Width; }
        }

        /// <summary>
        /// Gets the shape.
        /// </summary>
        public Shape Shape
        {
            get { return _mediaShape; }
        }

        /// <summary>
        /// Gets the name of the media.
        /// </summary>
        public string MediaName
        {
            get { return _mediaName; }
        }

        /// <summary>
        /// Gets or sets the duration of the fade.
        /// </summary>
        public float FadeDuration
        {
            get 
            { 
                if (string.IsNullOrEmpty(_mediaShape.Tags[MediaShapeTags.MediaShapeFadeDuration]))
                {
                    FadeDuration = Properties.Settings.Default.DefaultFadeDuration;
                }
                return float.Parse(_mediaShape.Tags[MediaShapeTags.MediaShapeFadeDuration]);

            }
            set { _mediaShape.Tags.Add(MediaShapeTags.MediaShapeFadeDuration, value.ToString()); }
        }

        /// <summary>
        /// Gets or sets the transparency of captions.
        /// </summary>
        public float Transparency
        {
            get 
            { 
                if (string.IsNullOrEmpty(_mediaShape.Tags[MediaShapeTags.MediaShapeTransparency]))
                {
                    Transparency = Properties.Settings.Default.DefaultTransparency;
                }
                return float.Parse(_mediaShape.Tags[MediaShapeTags.MediaShapeTransparency]);

            }
            set { _mediaShape.Tags.Add(MediaShapeTags.MediaShapeTransparency, value.ToString()); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the user should be prompted for captions.
        /// </summary>
        public bool PromptForCaptions
        {
            get
            {
                return !HasSavedCaptions && string.IsNullOrEmpty(_mediaShape.Tags[MediaShapeTags.MediaShapePromptForCaptions]);
            }
            set
            {
                _mediaShape.Tags.Add(MediaShapeTags.MediaShapePromptForCaptions, value.ToString());
            }
        }

        /// <summary>
        /// Gets or sets the caption alignement.
        /// </summary>
        public CaptionAlignment CaptionAlignment
        {
            get
            {
                CaptionAlignment captionAlignment;
                Enum.TryParse(_mediaShape.Tags[MediaShapeTags.MediaCaptionAlignment], true, out captionAlignment);
                return captionAlignment;
            }
            set { _mediaShape.Tags.Add(MediaShapeTags.MediaCaptionAlignment, value.ToString()); }
        }

        /// <summary>
        /// Deletes all references to the stored Captions
        /// </summary>
        public void DeleteStoredCaptionsAndIdTags()
        {
            DeleteStoredCaptions();
            _mediaShape.Tags.Delete(MediaShapeTags.CaptionMediaId);
            _mediaShape.Tags.Delete(MediaShapeTags.CustomXMLPartId);
            _mediaShape.Tags.Delete(MediaShapeTags.MediaCaptionsHidden);
            _mediaShape.Tags.Delete(MediaShapeTags.MediaShapeHasCaptions);
            _mediaShape.Tags.Delete(MediaShapeTags.MediaShapeFadeDuration);
            _mediaShape.Tags.Delete(MediaShapeTags.MediaShapeTransparency);
            _mediaShape.Tags.Delete(MediaShapeTags.MediaCaptionAlignment);
        }

        /// <summary>
        /// Deletes the stored captions.
        /// </summary>
        public void DeleteStoredCaptions()
        {
            string id = CustomXMLPartId;
            if (!String.IsNullOrEmpty(id))
                _mediaShape.Application.ActivePresentation.CustomXMLParts.SelectByID(id).Delete();
        }

        /// <summary>
        /// Shows the captions.
        /// </summary>
        public void ShowCaptions()
        {
            _mediaShape.Tags.Add(MediaShapeTags.MediaCaptionsHidden, false.ToString());
        }

        /// <summary>
        /// Hides the captions.
        /// </summary>
        public void HideCaptions()
        {
            _mediaShape.Tags.Add(MediaShapeTags.MediaCaptionsHidden, true.ToString());
        }

        /// <summary>
        /// Deletes the name of the bookmark by.
        /// </summary>
        /// <param name="bookmarkName">Name of the bookmark.</param>
        public void DeleteBookmarkByName(string bookmarkName)
        {
            for (int i = _mediaShape.MediaFormat.MediaBookmarks.Count; i >= 1; i--)
            {
                if (_mediaShape.MediaFormat.MediaBookmarks[i].Name.Equals(bookmarkName))
                {
                    _mediaShape.MediaFormat.MediaBookmarks[i].Delete();
                    break;
                }
            }
        }

        /// <summary>
        /// Adds the entry and exit book marks for the given caption.
        /// </summary>
        /// <param name="caption">The caption.</param>
        public void AddBookMarks(CaptionItem caption)
        {
            AddBookMark(caption.BookMarkEntryPosition, caption.BookMarkEntryName);
            AddBookMark(caption.BookMarkExitPosition, caption.BookMarkExitName);
        }

        private void AddBookMark(int position, string name)
        {
            if (!HasBookMark(name))
            {
                _mediaShape.MediaFormat.MediaBookmarks.Add(position, name);
            }
        }

        private bool HasBookMark(string name)
        {
            return _mediaShape.MediaFormat.MediaBookmarks.Cast<MediaBookmark>().Any(bookmark => bookmark.Name.Equals(name));
        }

        /// <summary>
        /// Deletes the bookmarks.
        /// </summary>
        public void DeleteBookmarks()
        {
            for (int i = (_mediaShape).MediaFormat.MediaBookmarks.Count; i >= 1; i--)
            {
                if (ShapeFinder.MatchName(_mediaShape.MediaFormat.MediaBookmarks[i].Name, MediaName))
                    _mediaShape.MediaFormat.MediaBookmarks[i].Delete();
            }
        }

        /// <summary>
        /// Adds the auto play effect.
        /// </summary>
        /// <param name="sequence">The sequence.</param>
        public void AddAutoPlayEffect(Sequence sequence)
        {
            Effect autoplayEffect = sequence.AddEffect(_mediaShape, MsoAnimEffect.msoAnimEffectMediaPlay);
            autoplayEffect.Timing.TriggerType = MsoAnimTriggerType.msoAnimTriggerAfterPrevious;
        }

        /// <summary>
        /// Determines whether the given effect is an autoplay effect of the current slide.
        /// </summary>
        public bool HasAutoplayEffect(Effect effect)
        {
            return effect.EffectType == MsoAnimEffect.msoAnimEffectMediaPlay && effect.Shape.Name == _mediaShape.Name;
        }
    }
}